import { sleep } from './sleep'
import * as IDB from 'idb'
// MyIndexedDB 配置选项
export interface CreateObjectStoreConfigOptions
  extends IDBObjectStoreParameters {
  autoIncrement?: boolean
  keyPath?: string | string[] | null
  // ↓自定义字段↓
  // 索引字段，用于创建索引
  index?: string[]
  // 一个函数，在首次创建数据存储对象后执行
  afterCreateHooks?: (instance: IDB.IDBPDatabase<any>) => void
}

/**
 * MyIndexedDB 数据库简单单例操作类（使用前必须先调用open方法）
 */
export class MyIndexedDB {
  // 单store模式，默认的存储表名称
  static readonly STORE_NAME = 'store'
  static instance: IDB.IDBPDatabase<any> | null = null
  /**
   * 初始化 MyIndexedDB 数据库并创建数据存储对象(单store模式)
   * @param dbName 数据库名称
   * @param config 可选参数，用于配置数据存储对象（CreateObjectStoreConfigOptions 类型），默认为 undefined
   * @returns 返回 IDB.IDBPDatabase<any> 对象
   */
  static async open(
    dbName: string,
    config?: CreateObjectStoreConfigOptions | undefined,
  ) {
    MyIndexedDB.instance = await IDB.openDB<any>(dbName, 1, {
      // 创建数据库或更新版本会执行upgrade,因此多store模式需要额外调用创建store的方法
      async upgrade(db, oldVersion, newVersion, transaction) {
        try {
          if (db.objectStoreNames.contains(MyIndexedDB.STORE_NAME)) {
            return db
          }
          const store = db.createObjectStore(MyIndexedDB.STORE_NAME, config)
          if (config?.index?.length) {
            config?.index.forEach((item) => {
              store.createIndex(`${dbName}__index__${item}`, item)
            })
          }
          if (config?.afterCreateHooks) {
            await sleep(100)
            config.afterCreateHooks(db)
          }
        }
        catch (error) {
          console.error('indexedDB 创建store失败，', error)
        }
        console.log(`indexedDB 数据库：${dbName}， 表: ${MyIndexedDB.STORE_NAME} 创建完成`)
      },
    })
    return MyIndexedDB.instance
  }

  /**
   * 关闭 MyIndexedDB 数据库连接
   */
  static close() {
    MyIndexedDB.instance?.close()
    MyIndexedDB.instance = null
  }

  /**
   * 获取事务对象
   * @returns 返回事务对象
   */
  static getTransaction() {
    const transaction = MyIndexedDB.instance?.transaction(MyIndexedDB.STORE_NAME, 'readwrite')
    return transaction
  }

  /**
   * 获取库表对象
   * @returns 返回库表对象
   */
  static getStore() {
    const transaction = MyIndexedDB.instance?.transaction(MyIndexedDB.STORE_NAME, 'readwrite')
    return transaction?.store
  }
}
